package com.hsy.crm.web.utils;

import com.hsy.crm.web.domain.cm.App;
import com.hsy.crm.web.domain.cm.NotInit;
import com.hsy.crm.web.domain.cm.Validate;
import com.hsy.crm.web.domain.entity.BaseEntity;
import com.hsy.crm.web.domain.ex.ServiceException;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;

import java.lang.reflect.Field;
import java.util.List;

/**
 * Created by admin on 2018/4/10.
 */
public class ServiceUtils {

    private ServiceUtils(){}

    public static void check(Object bean,int dbOperatorType){

            switch (dbOperatorType){
                case App.DbOperatorType.INSERT :
                    checkInsert(bean,dbOperatorType);
                    break;
                case App.DbOperatorType.DELETE :
                    checkDelete(bean,dbOperatorType);
                    break;
                case App.DbOperatorType.UPDATE :
                    checkUpdate(bean,dbOperatorType);
                    break;
                case App.DbOperatorType.SELECT :
                    checkSelect(bean,dbOperatorType);
                    break;
            }

    }

    public static void init_entity_insert(Object bean){
        PropertyUtils.setProperty(bean, App.Property.ID, UuidUtils.getUuid());

        init_company_id(bean);

        PropertyUtils.setProperty(bean, App.Property.CREATE_TIME,DateUtils.millis(),Boolean.FALSE);

        Long userId = ((BaseEntity)bean).getLoginUserId();
        PropertyUtils.setProperty(bean, App.Property.CREATE_USER_ID,userId,Boolean.FALSE);

        ServiceUtils.check(bean, App.DbOperatorType.INSERT);

        //check success after
        set_null_property(bean);
    }

    public static void init_entity_update(Object bean){
        PropertyUtils.setProperty(bean, App.Property.UPDATE_TIME, DateUtils.millis(),Boolean.FALSE);
        Object loginUserId = PropertyUtils.getProperty(bean, App.Property.LOGIN_USER_ID);
        PropertyUtils.setProperty(bean, App.Property.UPDATE_USER_ID,loginUserId,Boolean.FALSE);
        ServiceUtils.check(bean, App.DbOperatorType.UPDATE);
    }

    private static void init_company_id(Object bean){
        Field companyId = PropertyUtils.getField(bean.getClass(),App.Property.COMPNAY_ID);
        if( companyId == null ){
            return;
        }

        NotInit notInit = companyId.getAnnotation(NotInit.class);
        if( notInit != null ){
            return;
        }

        Object companyIdObj = PropertyUtils.getProperty(bean,App.Property.COMPNAY_ID);
        if( companyIdObj != null ){
            return;
        }

        Object loginCompanyId = PropertyUtils.getProperty(bean,App.Property.LOGIN_COMPNAY_ID);
        if( loginCompanyId != null ){
            PropertyUtils.setProperty(bean, App.Property.COMPNAY_ID,loginCompanyId);
        }
    }

    private static void set_null_property(Object bean){
        Field[] fields = FieldUtils.getAllFields(bean.getClass());
        for(Field field : fields){
            NotInit notInit = field.getAnnotation(NotInit.class);
            if( notInit == null ){
                if(is_not_base_property(field.getName())){
                    Object value = PropertyUtils.getProperty(bean,field.getName());
                    if( value == null ){
                        PropertyUtils.setProperty(bean,field.getName(),get_field_default_value(field));
                    }
                }
            }
        }
    }

    private static boolean is_not_base_property(String name){
        if( name.equals("id") || name.equals("customerId") || name.equals("page") || name.equals("limit")
                || name.equals("loginUserId") || name.equals("loginCompanyId") || name.equals("loginCompanyLogicalCode") || name.equals("examRoles")){
            return false;
        }
        return true;
    }

    private static Object get_field_default_value(Field field){
        String name = field.getType().getSimpleName();
        if( name.equals("Long") ){
            return App.DbDefaultValue.BIGINT;
        }else if( name.equals("String") ){
            return App.DbDefaultValue.CHAR;
        }else if( name.equals("Integer") ){
            return App.DbDefaultValue.INT;
        }else if( name.equals("Double") ){
            return App.DbDefaultValue.DOUBEL;
        }else{
            throw new ServiceException("set default value error"+field.getName());
        }
    }

    private static void checkInsert(Object bean,int dbOperatorType) {
        checkId(bean);
        checkField(bean,dbOperatorType);
    }

    private static void checkDelete(Object bean,int dbOperatorType) {
        checkId(bean);
        checkField(bean,dbOperatorType);
    }

    private static void checkUpdate(Object bean,int dbOperatorType) {
        checkId(bean);
        checkField(bean,dbOperatorType);
    }

    private static void checkSelect(Object bean,int dbOperatorType){
    }

    private static void checkId(Object bean){
        BaseEntity entity = (BaseEntity) bean;
        if( entity.getId()==null ){
            throw new ServiceException("param id is null");
        }
    }

    private static void checkField(Object bean,int dbOperatorType)  {
        List<Field> fields = FieldUtils.getFieldsListWithAnnotation(bean.getClass(), Validate.class);
        for( Field field : fields ){
            Validate validate = field.getAnnotation(Validate.class);
            if(getValidate(validate,dbOperatorType)){
                Object obj = PropertyUtils.getProperty(bean,field.getName());
                checkPropertyValue(obj,field.getName());
            }
        }
    }

    private static boolean getValidate(Validate validate,int dbOperatorType){

        if(validate==null){
            return false;
        }

        boolean flag = false;
        switch (dbOperatorType){
            case App.DbOperatorType.INSERT :
                flag = validate.insert();
                break;
            case App.DbOperatorType.DELETE :
                flag = validate.delete();
                break;
            case App.DbOperatorType.UPDATE :
                flag = validate.update();
                break;
            case App.DbOperatorType.SELECT :
                flag = validate.select();
                break;
        }
        return flag;
    }

    private static void checkPropertyValue(Object obj,String name){
        if( obj==null){
            throw new ServiceException("param ["+name+"] is null");
        }
        String value = obj.toString();
        if( StringUtils.isBlank(value)  ){
            throw new ServiceException("param ["+name+"] is null");
        }
    }

}
